package com.excel;

import com.excel.base.IWmsDownload;
import com.excel.base.IWmsUpload;
import com.excel.data.CheckExcelRowDTO;
import com.excel.utils.ExcelUtils;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static com.excel.utils.Cent.TWO;

/**
 * @author yutao
 * @since 2020/4/30 10:46 上午
 */
public class ExcelStockCheckService implements IWmsDownload<CheckExcelRowDTO>, IWmsUpload<CheckExcelRowDTO> {

    private ExcelHeader excelHeader;

    public void setStockUnitType(Integer stockUnitType) {
        excelHeader = ExcelHeader.findType(stockUnitType);
    }

    // -------------------------------------顶级表头--------------------------

    private static final String[] TOP_HEADER_NAME = {
            "门诊ID", "是否是诊室", "盘点项类型", "盘点项类型编号"
    };

    private static final String[] TOP_HEADER_FIELD = {
            "storeId", "isRoom", "unitTypeName", "unitTypeId"
    };
    // -------------------------------------顶级表头--------------------------

    // 导出 下载

    @Override
    public String[] getHeaderNames() {
        return excelHeader.getHeaderName();
    }

    @Override
    public String[] getTopHeaderNames() {
        return TOP_HEADER_NAME;
    }

    @Override
    public String[] getColumns() {
        return excelHeader.getDownloadField();
    }

    // 导入 上传

    @Override
    public String getPropertyName(int propertyIndex) {
        return excelHeader.getUploadField()[propertyIndex];
    }

    @Override
    public Integer getUploadFieldSize() {
        return excelHeader.getUploadField().length;
    }

    @Override
    public String[] getTopHeadFiled() {
        return TOP_HEADER_FIELD;
    }

    @Override
    public CheckExcelRowDTO createStock() {
        return new CheckExcelRowDTO();
    }

    @Override
    public void postStockInitialization(XSSFRow row, CheckExcelRowDTO stock) {

    }

    /**
     * 设置Integer类型值
     */
    @Override
    public void handleIntegerType(Method setter, CheckExcelRowDTO checkExcelRowDTO, String propertyName, String value)
            throws ReflectiveOperationException {
        if (COST.equals(propertyName) || PRICE.equals(propertyName)) {
            value = String.valueOf(Math.round(Double.parseDouble(value) * PRECISION));
        }
        setter.invoke(checkExcelRowDTO, Integer.valueOf(value));
    }

    /**
     * 上传库存excel
     * @param workbook
     * @param checkFirstColumn 校验第一列标志
     */
    @SuppressWarnings({"checkstyle:methodlength", "PMD.MethodTooLongRule"})
    public List<CheckExcelRowDTO> uploadTipError(XSSFWorkbook workbook, boolean checkFirstColumn) {
        List<CheckExcelRowDTO> stocks = Lists.newArrayList();
        // 外层是遍历sheet的个数
        for (int i = 0, sheets = workbook.getNumberOfSheets(); i < sheets; i++) {
            XSSFSheet childSheet = workbook.getSheetAt(i);
            // 创建实例对象
            CheckExcelRowDTO topStock = createStock();
            // 顶级表头单独处理
            setHeaderRows(getTopHeadFiled(), childSheet, topStock);
            setStockUnitType(topStock.getUnitTypeId());
            // 遍历单个sheet中的数据
            for (int r = TWO, rows = childSheet.getPhysicalNumberOfRows(); r < rows; r++) {
                CheckExcelRowDTO stock = createStock();
                XSSFRow row = childSheet.getRow(r);
                stock.setUnitTypeName(topStock.getUnitTypeName());
                stock.setUnitTypeId(topStock.getUnitTypeId());
                stock.setIsRoom(topStock.getIsRoom());
                stock.setStoreId(topStock.getStoreId());
                stock.setSheetId(i);
                stock.setRowId(r);

                if (continueFirstColumn(checkFirstColumn, row)) {
                    continue;
                }
                // 开始遍历真正的数据组装进对象中
                additionCellValue(stock, row);
                Optional.ofNullable(stock.isHappenedError()).filter(f -> f)
                        .ifPresent(no -> stock.setErrorMessage("数据格式错误"));
                postStockInitialization(row, stock);
                stocks.add(stock);
            }
        }
        return stocks;
    }

    public boolean continueFirstColumn(boolean checkFirstColumn, XSSFRow row) {
        return Optional.of(checkFirstColumn).filter(f -> f).map(m -> {
            if (row == null || row.getCell(0) == null) {
                return true;
            }
            row.getCell(0).setCellType(CellType.STRING);
            if (StringUtils.isBlank(row.getCell(0).getStringCellValue())) {
                return true;
            }
            return false;
        }).orElse(false);
    }

    @SuppressWarnings("checkstyle:MethodLength")
    public void additionCellValue(CheckExcelRowDTO stock, XSSFRow row) {
        int cellIndex = 0;
        try {
            // 开始遍历真正的数据组装进对象中
            for (; cellIndex < getUploadFieldSize(); cellIndex++) {
                // 得到属性名称
                String propertyName = getPropertyName(cellIndex);
                Cell cell = row.getCell(cellIndex);
                if (cell == null || StringUtils.isBlank(propertyName)) {
                    continue;
                }
                String value;
                if (CellType.NUMERIC.equals(cell.getCellTypeEnum())) {
                    value = ExcelUtils.doubleValueToString(cell.getNumericCellValue());
                } else {
                    cell.setCellType(CellType.STRING);
                    value = row.getCell(cellIndex).getStringCellValue().trim();
                }
                if (StringUtils.isBlank(value)) {
                    continue;
                }
                PropertyDescriptor propertyDescriptor = BeanUtils
                        .getPropertyDescriptor(stock.getClass(), propertyName);
                assert propertyDescriptor != null;
                Method method = propertyDescriptor.getWriteMethod();
                Class type = method.getParameterTypes()[0];
                if (type.isEnum()) {
                    handleEnumType(method, stock, type, value);
                    continue;
                }
                switch (type.getSimpleName()) {
                    case "String":
                        handleStringType(method, stock, propertyName, value);
                        break;
                    case "Long":
                        handleLongType(method, stock, propertyName, value);
                        break;
                    case "Integer":
                        handleIntegerType(method, stock, propertyName, value);
                        break;
                    case "Short":
                        handleShortType(method, stock, propertyName, value);
                        break;
                    case "BigDecimal":
                        handleBigDecimalType(method, stock, propertyName, value);
                        break;
                    case "List":
                        handleListType(method, stock, propertyName, value);
                        break;
                    case "Boolean":
                        handleBooleanType(method, stock, propertyName, value);
                        break;
                    case "OffsetDateTime":
                        handleOffsetDateTimeType(method, stock, propertyName, value);
                        break;
                    case "Byte":
                        method.invoke(stock, Byte.valueOf(Objects.requireNonNull(value)));
                        break;
                    default:
                        stock.getErrorCellIds().add(cellIndex);
                }
            }
        } catch (Exception e) {
            stock.getErrorCellIds().add(cellIndex);
        }
    }

}
